﻿using System;
using System.Collections.Generic;
using System.Text;

using Working.Domínio.Produtos;
using Working.Domínio.Pagamentos;

namespace Working.Domínio.Vendas
{
    public class Venda: Entidade
    {
        public Venda()
        {
            this.itens = new List<ItemDeVenda>();
            this.DataInícioDaVenda = DateTime.Now;
            this.DataFimDaVenda = DateTime.MinValue;
            this.pagamento = null;
            this.estáCompleta = false;
            this.estáFinalizada = false;
        }
        
        public List<ItemDeVenda> Itens
        {
            get { return itens; }
        } private List<ItemDeVenda> itens;

        public DateTime DataInícioDaVenda
        {
            get { return dataInícioDaVenda; }
            set 
            {
                //Necessário procedimento para manter a precisão da data em segundos
                this.dataInícioDaVenda = new DateTime(value.Year, value.Month, value.Day, 
                    value.Hour, value.Minute, value.Second);
            }
        } private DateTime dataInícioDaVenda;

        public DateTime DataFimDaVenda
        {
            get { return dataFimDaVenda; }
            set 
            {
                //Necessário procedimento para manter a precisão da data em segundos
                this.dataFimDaVenda = new DateTime(value.Year, value.Month, value.Day,
                    value.Hour, value.Minute, value.Second);
            }
        } private DateTime dataFimDaVenda;

        public Pagamento Pagamento
        {
            get { return this.pagamento; }
        } private Pagamento pagamento;

        public TimeSpan Duração
        {
            get 
            {
                DateTime data = DateTime.MinValue;
                TimeSpan tempoDeDuração;
                if (this.dataFimDaVenda.Equals(DateTime.MinValue))
                    tempoDeDuração = DateTime.Now.Subtract(this.DataInícioDaVenda);
                else
                    tempoDeDuração = this.dataFimDaVenda.Subtract(this.DataInícioDaVenda);

                //Retorna o tempo de duração da venda com precisão de segundos
                return new TimeSpan(tempoDeDuração.Hours, tempoDeDuração.Minutes, tempoDeDuração.Seconds);

            }
        }

        public bool EstáFinalizada
        {
            get { return this.estáFinalizada; }
        } private bool estáFinalizada;

        public bool EstáCompleta
        {
            get { return this.estáCompleta; }
        } private bool estáCompleta;


        public decimal Total
        {
            get{return CalcularTotal();}
        }


        public virtual void AdicionarItem(Produto produto)
        {
            AdicionarItem(produto, 1);
        }

        public void AdicionarItem(Produto produto, int quantidade)
        {
            if (produto == null)
                throw new ApplicationException(VendasResources.SProdutoNãoPodeSerNulo);

            if (quantidade <= 0)
                throw new QuantidadeDeItensInválidaException(quantidade);

            itens.Add(new ItemDeVenda(produto, quantidade));
        }


        /// <summary>
        /// Finaliza a entrada de itens e prepara venda para realizar o pagamento
        /// </summary>
        public virtual void Completar()
        {
            //Finaliza cálculos da venda e lança impostos finais
            //...

            this.estáCompleta = true;
        }

        public virtual void FazerPagamento(decimal quantiaFornecida)
        {
            this.pagamento = new PagamentoEmDinheiro(quantiaFornecida);
        }

        public virtual decimal Saldo()
        {
            if (Pagamento == null)
                return this.Total * -1;
            else
                return this.Pagamento.Quantia - this.Total;
        }

        public void Finalizar()
        {
            if (!this.EstáCompleta)
                this.Completar();

            //Verifica se venda possui itens associados
            if (this.Itens.Count == 0)
                throw new NenhumItemAdicionadoAVendaException(this);

            //Verifica se pagamento foi realizado
            if (this.Saldo() < 0)
                throw new PagamentoDaVendaNãoRealizadoException(this);

            this.DataFimDaVenda = DateTime.Now;
            this.estáFinalizada = true;
        }

        protected decimal CalcularTotal()
        {
            decimal total = 0M;
            foreach (ItemDeVenda item in this.itens)
                total += item.SubTotal;

            return total;
        }
    }
}
